package IndexingLucene;

import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;

import org.apache.lucene.analysis.core.WhitespaceAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;

public class MyIndexWriter {
	
	protected File dir;
	private Directory directory;
	
	/**
	 * [class] index.IndexWriter:
	 * An IndexWriter creates and maintains an index.
	 */
	private IndexWriter iwriter;
	
	/**
	 * [class] document.FieldType:
	 * Describes the properties of a field.
	 */
	private FieldType type;
	
	/**
	 * Initiate index writer.
	 * 
	 * @param dataType
	 * @throws IOException
	 */
	public MyIndexWriter(String dataType) throws IOException {
		// 1. Open directory of collection needing indexing
		if (dataType.equals("trectext")) {
			directory = FSDirectory.open(Paths.get(Classes.Path.IndexTextDir));  
		} else {
			directory = FSDirectory.open(Paths.get(Classes.Path.IndexWebDir)); 
		}
		
		/**
		 * [class] index.IndexWriterConfig:
		 * Holds all the configuration that is used to create an IndexWriter. 
		 * Once IndexWriter has been created with this object, changes to 
		 * this object will not affect the IndexWriterinstance.
		 * 		 
		 * [constructor] IndexWriterConfig(Analyzer analyzer):
		 * Creates a new config that with the provided Analyzer.
		 * 
		 * [class] analysis.core.WhitespaceAnalyzer:
		 * An Analyzer that uses WhitespaceTokenizer.
		 * 
		 * [class] analysis.core.WhitespaceTokenizer:
		 * A tokenizer that divides text at whitespace characters as defined by 
		 * Character.isWhitespace(int). 
		 * Note: That definition explicitly excludes the non-breaking space. 
		 * Adjacent sequences of non-Whitespace characters form tokens.
		 */
		// 2. Configure index writer
		// 2.1 Set WhitespaceAnanlyzer for tokenization
		IndexWriterConfig indexConfig = new IndexWriterConfig(new WhitespaceAnalyzer());
		/**
		 * [method] IndexWriterConfig IndexWriterConfig.setMaxBufferedDocs(int maxBufferedDocs):
		 * Determines the minimal number of documents required before the buffered in-memory 
		 * documents are flushed as a new Segment.
		 */
		// 2.2 Set the maxium buffered docs. One exceed this number, flush to hard disk
		indexConfig.setMaxBufferedDocs(10000);
		// 2.3 Configure index writer with given directory and index configuration
		iwriter = new IndexWriter(directory, indexConfig);
		
		//3. Configure field type
		type = new FieldType();
		/** 
		 * [method] void FieldType.setIndexOptions(IndexOptions value):
		 * Sets the indexing options for the field.
		 * 
		 * [class] index.IndexOptions:
		 * Controls how much information is stored in the postings lists.
		 * 
		 * [constant] IndexOptions.[constant_value]:
		 * DOCS - Only documents are indexed: term frequencies and positions are omitted.
		 * DOCS_AND_FREQS - Only documents and term frequencies are indexed: positions are omitted.
		 * DOCS_AND_FREQS_AND_POSITIONS - Indexes documents, frequencies and positions.
		 * DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS - Indexes documents, frequencies, positions and offsets.
		 * NONE - Not indexed.
		 */
		type.setIndexOptions(IndexOptions.DOCS_AND_FREQS);
		/**
		 * [method] void FieldType.setStored(boolean value):
		 * Set to true to store this field.
		 */
		type.setStored(false);
		/**
		 * [method] void FieldType.setStoreTermVectors(boolean value):
		 * Set to true if this field's indexed form should be also stored into term vectors.
		 * 
		 * [method] boolean FieldType.storeTermVectors():
		 * True if this field's indexed form should be also stored into term vectors.
         * This builds a miniature inverted-index for this field which can be accessed 
         * in a document-oriented way from IndexReader.getTermVector(int, String).
         * This option is illegal if IndexableFieldType.indexOptions() returns IndexOptions.NONE.
         * The default is false.
		 */
		type.setStoreTermVectors(true);
	}
	
	/**
	 * This method build index for each document.
	 * NOTE: In your implementation of the index, you should transform your string 
	 * docnos into non-negative integer docids;
	 * In MyIndexReader, you should be able to request the integer docid for docnos.
	 * 
	 * @param docno 
	 * @param content
	 * @throws IOException
	 */
	public void index(String docno, char[] content) throws IOException {
		// 1. Create an empty document object
		Document doc = new Document();
		/**
		 * [class] document.StoredField:
		 * A field whose value is stored so that IndexSearcher.doc(int) and 
		 * IndexReader.document() will return the field and its value.
		 * 使用StoredField时，根本不会发生索引。该文件只是存储。
		 * 
		 * [method] Document IndexReader.document(int docID):
		 * Returns the stored fields of the nth Document in this index.
		 */
		// 2. Add fields to the document object
		doc.add(new StoredField("DOCNO", docno));	
		/**
		 * [class] document.Field:
		 * A field is a section of a Document. Each field has three parts: name, type and value. 
		 * Values may be text (String, Reader or pre-analyzed TokenStream), binary (byte[]), or numeric (a Number). 
		 * 
		 * Fields are optionally stored in the index, so that they may be returned with hits on the document.
         * 
         * NOTE: the field type is an IndexableFieldType. 
         * Making changes to the state of the IndexableFieldType will impact any Field it is used in. 
         * It is strongly recommended that no changes be made after Field instantiation.
		 */
		doc.add(new Field("CONTENT", new String(content), type)); // A field's name, value, type respectively
		// 3. Write index of the document object
		iwriter.addDocument(doc);
	}
	
	/**
	 * Close the index writer, and you should output all the buffered content (if any).
	 * 
	 * @throws IOException
	 */
	public void close() throws IOException {
		iwriter.close();
		directory.close();
	}	
}
